import time
import os
import psutil
import subprocess
from datetime import datetime
import logging
import signal
import sys
import threading
import pyudev
from http_server import HttpServer

# 导入GPIO监控模块
try:
    from gpio_monitor import GPIOMonitor
    import gpiod
    GPIO_AVAILABLE = True
except ImportError:
    logging.warning("GPIO监控模块不可用，将使用默认模式")
    GPIO_AVAILABLE = False

# 导入SD卡监控模块
try:
    from sd_monitor import SDMonitor
    SD_MONITOR_AVAILABLE = True
except ImportError:
    logging.warning("SD卡监控模块不可用，将使用默认模式")
    SD_MONITOR_AVAILABLE = False

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/log/app.log'),
        logging.StreamHandler()
    ]
)

class VideoRecorder:
    def __init__(self, usb_device=None, rtsp_url="rtsp://localhost:8554/stream",
                 output_dir="/media/sdcard/recordings", segment_duration=1200, root_dir='/media/sdcard/recordings',
                 button_pin=1, enable_gpio=True, enable_hdmi_display=True, auto_detect=True):
        # 自动检测USB设备
        if auto_detect and usb_device is None:
            self.usb_device = self._auto_detect_usb_device()
        else:
            self.usb_device = usb_device or '/dev/video0'
        
        self.rtsp_url = rtsp_url
        self.output_dir = output_dir
        self.segment_duration = segment_duration
        self.is_recording = False
        self.current_file = None
        self.rtsp_process = None
        self.ffmpeg_process = None
        self.monitor_thread = None
        self.device_monitor = None
        self.http_server_thread = None
        self.root_dir = os.path.abspath(root_dir)  # 确保使用绝对路径
        self.current_stream = None  # 当前推流进程
        self.auto_detect = auto_detect  # 是否启用自动检测
        self.device_polling_thread = None  # 设备轮询线程
        self.device_polling_interval = 5  # 轮询间隔（秒）
        self.device_polling_active = False  # 轮询状态标志
        
        # GPIO相关变量
        self.enable_gpio = enable_gpio and GPIO_AVAILABLE
        self.button_pin = button_pin
        self.gpio_monitor = None
        
        # SD卡监控相关变量
        self.enable_sd_monitor = SD_MONITOR_AVAILABLE
        self.sd_monitor = None
        self.sd_monitor_thread = None
        
        # FFmpeg错误监控相关变量
        self.error_monitor_thread = None
        
        # 创建输出目录并设置权限
        os.makedirs(self.output_dir, exist_ok=True)
        os.chmod(self.output_dir, 0o777)
        
        # 创建HTTP服务器实例
        self.server = HttpServer(
            root_dir=self.root_dir,
            on_push=self.handle_push_request,
            on_stop=self.handle_stop_request
        )
        
        # 确保根目录存在
        if not os.path.exists(self.root_dir):
            raise Exception(f"根目录不存在: {self.root_dir}")
            
        # 确保根目录可访问
        if not os.access(self.root_dir, os.R_OK):
            raise Exception(f"根目录不可访问: {self.root_dir}")
            
        logging.info(f"初始化完成，根目录: {self.root_dir}")
        logging.info(f"USB设备: {self.usb_device}")
        
        # 初始化GPIO
        if self.enable_gpio:
            self._init_gpio()
        
        # 初始化SD卡监控
        if self.enable_sd_monitor:
            self._init_sd_monitor()
        
        # 设置信号处理
        signal.signal(signal.SIGINT, self.signal_handler)
        signal.signal(signal.SIGTERM, self.signal_handler)

        # HDMI显示配置
        self.enable_hdmi_display = enable_hdmi_display

    def _auto_detect_usb_device(self):
        """自动检测可用的USB视频设备"""
        logging.info("开始自动检测USB视频设备...")
        
        # 轮询 /dev/video0-4
        for i in range(5):  # video0 到 video4
            device_path = f'/dev/video{i}'
            if self._is_device_available(device_path):
                logging.info(f"找到可用设备: {device_path}")
                return device_path
        
        logging.warning("未找到可用的USB视频设备，使用默认设备 /dev/video0")
        return '/dev/video0'

    def _is_device_available(self, device_path):
        """检查设备是否可用"""
        try:
            # 检查设备文件是否存在
            if not os.path.exists(device_path):
                return False
            
            # 检查设备是否被占用
            try:
                result = subprocess.run(['lsof', device_path], 
                                      capture_output=True, text=True, timeout=2)
                if result.stdout.strip():
                    logging.debug(f"设备 {device_path} 被占用")
                    return False
            except (subprocess.TimeoutExpired, FileNotFoundError):
                # lsof 命令不可用或超时，继续检查
                pass
            
            # 尝试获取设备信息
            try:
                result = subprocess.run(['v4l2-ctl', '--device', device_path, '--list-formats-ext'], 
                                      capture_output=True, text=True, timeout=3)
                if result.returncode == 0 and result.stdout.strip():
                    logging.debug(f"设备 {device_path} 支持视频格式")
                    return True
            except (subprocess.TimeoutExpired, FileNotFoundError):
                # v4l2-ctl 命令不可用或超时
                pass
            
            # 检查设备是否为USB设备
            try:
                context = pyudev.Context()
                device = pyudev.Devices.from_device_file(context, device_path)
                if device.get('ID_VENDOR_ID') and device.get('ID_MODEL_ID'):
                    logging.debug(f"设备 {device_path} 是USB设备")
                    return True
            except Exception as e:
                logging.debug(f"检查设备 {device_path} 的USB属性失败: {e}")
            
            return False
            
        except Exception as e:
            logging.debug(f"检查设备 {device_path} 时发生错误: {e}")
            return False

    def _device_polling_worker(self):
        """设备轮询工作线程"""
        logging.info("设备轮询线程已启动")
        while self.device_polling_active:
            try:
                # 如果正在录像，暂停轮询
                if self.is_recording and self.ffmpeg_process and self.ffmpeg_process.poll() is None:
                    logging.debug("录像进行中，暂停设备轮询")
                    time.sleep(self.device_polling_interval)
                    continue
                
                # 检查当前设备是否仍然可用
                if not self._is_device_available(self.usb_device):
                    logging.warning(f"当前设备 {self.usb_device} 不可用，开始寻找新设备...")
                    
                    # 寻找新的可用设备
                    new_device = self._find_available_device()
                    if new_device and new_device != self.usb_device:
                        logging.info(f"找到新设备: {new_device}，切换到新设备")
                        self._switch_device(new_device)
                    elif not new_device:
                        logging.warning("未找到可用的视频设备")
                
                # 等待下一次轮询
                time.sleep(self.device_polling_interval)
                
            except Exception as e:
                logging.error(f"设备轮询过程中发生错误: {e}")
                time.sleep(self.device_polling_interval)

    def _find_available_device(self):
        """寻找可用的视频设备"""
        for i in range(5):  # video0 到 video4
            device_path = f'/dev/video{i}'
            if self._is_device_available(device_path):
                return device_path
        return None

    def _switch_device(self, new_device):
        """切换到新设备"""
        try:
            logging.info(f"正在切换到新设备: {new_device}")
            
            # 如果正在录制，先停止录制
            was_recording = self.is_recording
            if was_recording:
                logging.info("停止当前录制以切换设备")
                self.stop_recording()
            
            # 更新设备路径
            old_device = self.usb_device
            self.usb_device = new_device
            
            logging.info(f"设备已从 {old_device} 切换到 {new_device}")
            
            # 如果之前在录制，重新开始录制
            if was_recording:
                logging.info("重新开始录制")
                time.sleep(2)  # 等待设备稳定
                self.start_recording()
                
        except Exception as e:
            logging.error(f"切换设备失败: {e}")

    def start_device_polling(self):
        """启动设备轮询"""
        if not self.auto_detect:
            return
            
        if self.device_polling_thread and self.device_polling_thread.is_alive():
            logging.warning("设备轮询线程已在运行")
            return
            
        self.device_polling_active = True
        self.device_polling_thread = threading.Thread(target=self._device_polling_worker, daemon=True)
        self.device_polling_thread.start()
        logging.info("设备轮询已启动")

    def stop_device_polling(self):
        """停止设备轮询"""
        self.device_polling_active = False
        if self.device_polling_thread and self.device_polling_thread.is_alive():
            self.device_polling_thread.join(timeout=5.0)
            logging.info("设备轮询已停止")

    def manual_device_detection(self):
        """手动重新检测设备"""
        logging.info("开始手动设备检测...")
        
        # 寻找新的可用设备
        new_device = self._find_available_device()
        if new_device:
            if new_device != self.usb_device:
                logging.info(f"找到新设备: {new_device}，切换到新设备")
                self._switch_device(new_device)
                return True
            else:
                logging.info(f"当前设备 {self.usb_device} 仍然可用")
                return True
        else:
            logging.warning("未找到可用的视频设备")
            return False

    def get_available_devices(self):
        """获取所有可用的视频设备列表"""
        available_devices = []
        for i in range(5):  # video0 到 video4
            device_path = f'/dev/video{i}'
            if self._is_device_available(device_path):
                available_devices.append(device_path)
        return available_devices

    def _init_gpio(self):
        """初始化GPIO监控"""
        try:
            # 创建GPIO监控实例
            self.gpio_monitor = GPIOMonitor(
                chip_name='gpiochip3',
                button_pin=self.button_pin,
                long_press_sec=3
            )
            # 设置短按为开始录制，长按为停止录制
            self.gpio_monitor.set_callbacks(
                on_long_press=self._on_button_long_press,
                on_press=self._on_button_press
            )
            logging.info(f"GPIO监控初始化成功 - 芯片: gpiochip1, 按键: GPIO{self.button_pin}")
        except Exception as e:
            logging.error(f"GPIO监控初始化失败: {e}")
            self.enable_gpio = False
            self.gpio_monitor = None

    def _on_button_press(self):
        """按键短按回调 - 只负责开始录制"""
        if self.is_recording:
            logging.info("按键短按 - 已在录制中，忽略")
            return
        logging.info("按键短按 - 开始录制")
        self.start_recording()

    def _on_button_long_press(self):
        """按键长按回调 - 只负责停止录制"""
        if not self.is_recording:
            logging.info("按键长按 - 未在录制中，忽略")
            return
        logging.info("按键长按 - 停止录制")
        self.stop_recording()

    def start_gpio_monitoring(self):
        """开始GPIO监控"""
        if not self.enable_gpio or not self.gpio_monitor:
            return
            
        try:
            self.gpio_monitor.start()
            logging.info("GPIO监控已启动")
            
        except Exception as e:
            logging.error(f"启动GPIO监控失败: {e}")

    def stop_gpio_monitoring(self):
        """停止GPIO监控"""
        if not self.enable_gpio or not self.gpio_monitor:
            return
            
        try:
            self.gpio_monitor.stop()
            logging.info("GPIO监控已停止")
            
        except Exception as e:
            logging.error(f"停止GPIO监控失败: {e}")

    def _init_sd_monitor(self):
        """初始化SD卡监控"""
        try:
            # 创建SD卡监控实例
            self.sd_monitor = SDMonitor()
            logging.info("SD卡监控初始化成功")
            
        except Exception as e:
            logging.error(f"SD卡监控初始化失败: {e}")
            self.enable_sd_monitor = False
            self.sd_monitor = None

    def start_sd_monitoring(self):
        """开始SD卡监控"""
        if not self.enable_sd_monitor or not self.sd_monitor:
            return
            
        try:
            self.sd_monitor.start()
            logging.info("SD卡监控已启动")
            
        except Exception as e:
            logging.error(f"启动SD卡监控失败: {e}")

    def stop_sd_monitoring(self):
        """停止SD卡监控"""
        if not self.enable_sd_monitor or not self.sd_monitor:
            return
            
        try:
            self.sd_monitor.stop()
            logging.info("SD卡监控已停止")
            
        except Exception as e:
            logging.error(f"停止SD卡监控失败: {e}")

    def get_current_date_dir(self):
        """获取当前日期的目录路径"""
        date_dir = os.path.join(self.output_dir, datetime.now().strftime('%Y%m%d'))
        try:
            os.makedirs(date_dir, exist_ok=True)
            os.chmod(date_dir, 0o777)  # 设置目录权限
            return date_dir
        except Exception as e:
            logging.error(f"Error creating date directory: {e}")
            return self.output_dir  # 如果创建失败，返回主目录

    def get_storage_info(self):
        """获取存储空间信息"""
        try:
            disk = psutil.disk_usage(self.output_dir)
            return {
                'total': disk.total,
                'used': disk.used,
                'free': disk.free,
                'percent': disk.percent
            }
        except Exception as e:
            logging.error(f"Error getting storage info: {e}")
            return None

    def cleanup_old_files(self):
        """当存储空间不足时，删除最旧的一个视频文件"""
        try:
            storage_info = self.get_storage_info()
            if not storage_info:
                logging.warning("无法获取存储信息，跳过清理")
                return

            logging.info(f"当前磁盘使用率: {storage_info['percent']:.1f}%")
            
            if storage_info['percent'] > 80:  # 当使用率超过80%时清理
                logging.warning(f"磁盘使用率过高 ({storage_info['percent']:.1f}%)，开始删除最旧的视频文件...")
                
                # 获取所有日期目录
                date_dirs = [d for d in os.listdir(self.output_dir) 
                           if os.path.isdir(os.path.join(self.output_dir, d)) and d.isdigit()]
                date_dirs.sort()  # 按日期排序，最早的在前
                
                if not date_dirs:
                    logging.warning("没有找到日期目录，无法清理")
                    return
                
                logging.info(f"找到 {len(date_dirs)} 个日期目录，寻找最旧的视频文件")
                
                # 收集所有视频文件及其创建时间
                all_video_files = []
                for date_dir in date_dirs:
                    full_date_dir = os.path.join(self.output_dir, date_dir)
                    try:
                        files = [os.path.join(full_date_dir, f) for f in os.listdir(full_date_dir)
                                if f.endswith('.mp4')]
                        for file_path in files:
                            try:
                                ctime = os.path.getctime(file_path)
                                all_video_files.append((file_path, ctime))
                            except Exception as e:
                                logging.debug(f"获取文件 {file_path} 创建时间失败: {e}")
                    except Exception as e:
                        logging.debug(f"读取目录 {date_dir} 失败: {e}")
                
                if not all_video_files:
                    logging.warning("没有找到视频文件，无法清理")
                    return
                
                # 按创建时间排序，最旧的在前
                all_video_files.sort(key=lambda x: x[1])
                
                # 删除最旧的一个视频文件
                oldest_file_path, oldest_file_ctime = all_video_files[0]
                try:
                    file_size = os.path.getsize(oldest_file_path)
                    os.remove(oldest_file_path)
                    logging.info(f"已删除最旧的视频文件: {os.path.basename(oldest_file_path)} "
                               f"(大小: {file_size / 1024 / 1024:.1f}MB, "
                               f"创建时间: {datetime.fromtimestamp(oldest_file_ctime).strftime('%Y-%m-%d %H:%M:%S')})")
                    
                    # 检查文件所在目录是否为空，如果为空则删除目录
                    file_dir = os.path.dirname(oldest_file_path)
                    if not os.listdir(file_dir):
                        try:
                            os.rmdir(file_dir)
                            logging.info(f"删除空目录: {os.path.basename(file_dir)}")
                        except Exception as e:
                            logging.error(f"删除目录失败: {e}")
                    
                    # 获取清理后的存储信息
                    new_storage_info = self.get_storage_info()
                    if new_storage_info:
                        logging.info(f"清理完成，当前磁盘使用率: {new_storage_info['percent']:.1f}%")
                    else:
                        logging.warning("清理完成后无法获取存储信息")
                        
                except Exception as e:
                    logging.error(f"删除最旧文件失败: {e}")
                    
            else:
                logging.info(f"磁盘使用率正常 ({storage_info['percent']:.1f}%)，无需清理")
                            
        except Exception as e:
            logging.error(f"清理旧文件时发生错误: {e}")

    def start_rtsp_stream(self):
        """启动RTSP推流"""
        try:
            if self.rtsp_process and self.rtsp_process.poll() is None:
                self.rtsp_process.terminate()
                self.rtsp_process.wait()

            # 获取设备能力并选择最优设置
            capabilities = self._get_device_capabilities(self.usb_device)
            settings = self._select_optimal_settings(capabilities)

            command = [
                'ffmpeg',
                '-f', 'v4l2',
                '-input_format', settings['input_format'],
                '-video_size', settings['video_size'],
                '-framerate', settings['framerate'],
                '-i', self.usb_device,
                '-c:v', 'h264_rkmpp',
                '-f', 'rtsp',
                self.rtsp_url
            ]
            self.rtsp_process = subprocess.Popen(command)
            logging.info("RTSP stream started")
            logging.info(f"使用设备设置: 格式={settings['input_format']}, "
                        f"分辨率={settings['video_size']}, 帧率={settings['framerate']}")
        except Exception as e:
            logging.error(f"Error starting RTSP stream: {e}")

    def check_device(self):
        """检查设备是否可用"""
        return self._is_device_available(self.usb_device)

    def _get_device_capabilities(self, device_path):
        """获取设备支持的格式、分辨率和帧率"""
        try:
            # 使用v4l2-ctl获取设备支持的格式
            result = subprocess.run(['v4l2-ctl', '--device', device_path, '--list-formats-ext'], 
                                  capture_output=True, text=True, timeout=5)
            
            if result.returncode != 0:
                logging.warning(f"无法获取设备 {device_path} 的格式信息")
                return None
            
            capabilities = {
                'formats': [],
                'resolutions': [],
                'framerates': []
            }
            
            current_format = None
            lines = result.stdout.split('\n')
            
            for line in lines:
                line = line.strip()
                if line.startswith('['):
                    # 格式行，如 [0]: 'MJPG' (Motion-JPEG, compressed)
                    format_match = line.split("'")[1] if "'" in line else None
                    if format_match:
                        current_format = format_match
                        capabilities['formats'].append(current_format)
                elif line.startswith('Size:') and current_format:
                    # 分辨率行，如 Size: Discrete 1920x1080
                    size_match = line.split('Discrete ')[1] if 'Discrete ' in line else None
                    if size_match:
                        capabilities['resolutions'].append(size_match)
                elif line.startswith('Interval:') and current_format:
                    # 帧率行，如 Interval: Discrete 0.033s (30.000 fps)
                    fps_match = line.split('(')[1].split(' fps')[0] if '(' in line and ' fps' in line else None
                    if fps_match:
                        try:
                            fps = float(fps_match)
                            capabilities['framerates'].append(fps)
                        except ValueError:
                            pass
            
            logging.info(f"设备 {device_path} 支持: 格式={capabilities['formats']}, "
                        f"分辨率={capabilities['resolutions']}, 帧率={capabilities['framerates']}")
            
            return capabilities
            
        except Exception as e:
            logging.error(f"获取设备 {device_path} 能力时发生错误: {e}")
            return None

    def _select_optimal_settings(self, capabilities):
        """选择最优的设置"""
        if not capabilities:
            # 如果无法获取设备能力，使用默认设置
            return {
                'input_format': 'mjpeg',
                'video_size': '1280x1024',
                'framerate': '60'
            }
        
        # 选择格式优先级：MJPG > YUYV > 其他
        format_priority = ['YUYV', 'YUY2', 'UYVY', 'MJPG']
        selected_format = None
        
        for fmt in format_priority:
            if fmt in capabilities['formats']:
                # 将设备格式转换为FFmpeg识别的格式名称
                if fmt == 'MJPG':
                    selected_format = 'mjpeg'  # FFmpeg识别mjpeg
                elif fmt == 'YUYV':
                    selected_format = 'yuyv422'  # FFmpeg识别yuyv422
                elif fmt == 'YUY2':
                    selected_format = 'yuyv422'  # FFmpeg识别yuyv422
                elif fmt == 'UYVY':
                    selected_format = 'uyvy422'  # FFmpeg识别uyvy422
                else:
                    selected_format = fmt.lower()  # 其他格式转换为小写
                break
        
        if not selected_format and capabilities['formats']:
            # 如果优先级中没有找到，使用第一个可用格式
            first_format = capabilities['formats'][0]
            if first_format == 'MJPG':
                selected_format = 'mjpeg'
            elif first_format == 'YUYV':
                selected_format = 'yuyv422'
            elif first_format == 'YUY2':
                selected_format = 'yuyv422'
            elif first_format == 'UYVY':
                selected_format = 'uyvy422'
            else:
                selected_format = first_format.lower()
        elif not selected_format:
            selected_format = 'mjpeg'  # 默认格式
        
        # 选择分辨率优先级：优先1280x1024，且不能超过这个分辨率
        target_width, target_height = 1280, 1024
        selected_resolution = None
        
        # 首先尝试找到1280x1024
        if '1280x1024' in capabilities['resolutions']:
            selected_resolution = '1280x1024'
        else:
            # 如果没有1280x1024，选择不超过1280x1024的最大分辨率
            available_resolutions = []
            for res in capabilities['resolutions']:
                try:
                    width, height = map(int, res.split('x'))
                    if width <= target_width and height <= target_height:
                        available_resolutions.append((width, height, res))
                except (ValueError, IndexError):
                    continue
            
            if available_resolutions:
                # 按分辨率大小排序，选择最大的
                available_resolutions.sort(key=lambda x: x[0] * x[1], reverse=True)
                selected_resolution = available_resolutions[0][2]
        
        if not selected_resolution:
            selected_resolution = '1280x1024'  # 默认分辨率
        
        # 选择帧率优先级：30 > 25 > 其他
        framerate_priority = [60, 30, 25, 24]
        selected_framerate = None
        
        for fps in framerate_priority:
            if fps in capabilities['framerates']:
                selected_framerate = str(fps)
                break
        
        if not selected_framerate and capabilities['framerates']:
            selected_framerate = str(int(capabilities['framerates'][0]))
        elif not selected_framerate:
            selected_framerate = '60'  # 默认帧率
        
        settings = {
            'input_format': selected_format,
            'video_size': selected_resolution,
            'framerate': selected_framerate
        }
        
        logging.info(f"选择的设置: 格式={settings['input_format']}, "
                    f"分辨率={settings['video_size']}, 帧率={settings['framerate']}")
        
        return settings

    def start_ffmpeg_recording(self, date_dir):
        """使用GStreamer开始录制和推流"""
        try:
            if self.ffmpeg_process:
                self.ffmpeg_process.terminate()
                self.ffmpeg_process.wait()

            # 确保日期目录存在
            os.makedirs(date_dir, exist_ok=True)
            os.chmod(date_dir, 0o777)

            # 检查设备
            if not self.check_device():
                return False

            # 获取设备能力并选择最优设置
            capabilities = self._get_device_capabilities(self.usb_device)
            settings = self._select_optimal_settings(capabilities)

            # 设置GStreamer环境变量
            env = os.environ.copy()
            env.update({
                'GST_MPP_NO_RGA': '1',
                'GST_VIDEO_CONVERT_USE_RGA': '0',
                'GST_VIDEO_FLIP_USE_RGA': '0',
                'MPP_USE_RGA': '0'
            })
            
            # 生成带时间戳的文件名格式
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
            filename_pattern = f"recording_{timestamp}_%03d.mp4"
            
            # 构建GStreamer命令
            command = [
                'gst-launch-1.0',
                'v4l2src', f'device={self.usb_device}', '!',
                f'image/jpeg,width={settings["video_size"].split("x")[0]},height={settings["video_size"].split("x")[1]},framerate={settings["framerate"]}/1', '!',
                'queue', '!',
                'jpegdec', '!',
                'videoconvert', '!', 'video/x-raw,format=NV12', '!',
                'queue', '!',
                'mpph265enc', 'rc-mode=vbr', '!',
                'h265parse', '!',
                'tee', 'name=t', 'allow-not-linked=1',
                't.', '!', 'queue', 'leaky=2', '!',
                'splitmuxsink', 
                f'location={os.path.join(date_dir, filename_pattern)}',
                'max-size-time=1200000000000',
                'muxer="mp4mux name=mux fragment-duration=2000000000 faststart=true"',
                't.', '!', 'queue', 'leaky=2', '!',
                'rtspclientsink', f'location={self.rtsp_url}'
            ]
            
            logging.info(f"Starting GStreamer recording in directory: {date_dir}")
            logging.info(f"使用设备: {self.usb_device}")
            logging.info(f"选择的分辨率: {settings['video_size']}, 帧率: {settings['framerate']}")
            logging.info(f"GStreamer command: {' '.join(command)}")
            
            # 启动GStreamer进程
            self.ffmpeg_process = subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                stdin=subprocess.PIPE,
                env=env,
                preexec_fn=os.setsid  # 创建新的进程组
            )
            
            logging.info(f"GStreamer process started with PID: {self.ffmpeg_process.pid}")
            
            # 启动GStreamer错误监控线程
            self._start_ffmpeg_error_monitor()
            
            return True
            
        except Exception as e:
            logging.error(f"Error starting GStreamer recording: {e}")
            return False

    def start_device_monitor(self):
        """启动设备监控"""
        try:
            context = pyudev.Context()
            monitor = pyudev.Monitor.from_netlink(context)
            monitor.filter_by(subsystem='video4linux')
            
            def device_event(action, device):
                if action == 'add':
                    logging.info(f"Camera device added: {device.device_path}")
                    # 获取设备的符号链接
                    device_node = device.get('DEVNAME')
                    if device_node and device_node == self.usb_device:
                        # 等待设备完全初始化
                        time.sleep(2)
                        # 检查设备是否真的可用
                        if os.path.exists(self.usb_device):
                            logging.info("Camera is ready, starting recording and streaming")
                            # 使用线程来启动录制，避免阻塞事件循环
                            threading.Thread(target=self.start_recording, daemon=True).start()
                        else:
                            logging.warning("Camera device not ready yet")
                elif action == 'remove':
                    logging.info(f"Camera device removed: {device.device_path}")
                    # 获取设备的符号链接
                    device_node = device.get('DEVNAME')
                    if device_node and device_node == self.usb_device:
                        logging.info("Stopping recording and streaming due to camera removal")
                        # 使用线程来停止录制，避免阻塞事件循环
                        threading.Thread(target=self.stop_recording, daemon=True).start()
            
            observer = pyudev.MonitorObserver(monitor, device_event)
            observer.start()
            self.device_monitor = observer
            logging.info("Device monitor started")
        except Exception as e:
            logging.error(f"Error starting device monitor: {e}")

    def stop_device_monitor(self):
        """停止设备监控"""
        if self.device_monitor:
            self.device_monitor.stop()
            self.device_monitor = None
            logging.info("Device monitor stopped")

    def restart_recording(self):
        """重启录制"""
        logging.info("Restarting recording and streaming...")
        try:
            # 先停止当前进程
            self.stop()
            # 等待进程完全停止
            time.sleep(2)
            # 检查设备是否可用
            if os.path.exists(self.usb_device):
                # 重新启动录制和推流
                self.is_recording = True  # 确保标志被重置
                self.start()  # 使用原有的 start 方法
                logging.info("Recording and streaming restarted successfully")
            else:
                logging.error("Camera device not available for restart")
        except Exception as e:
            logging.error(f"Error restarting recording: {e}")

    def start_recording(self):
        """开始录制"""
        # 获取当前日期目录
        current_date_dir = self.get_current_date_dir()
        
        # 启动GStreamer录制
        if self.start_ffmpeg_recording(current_date_dir):
            self.is_recording = True
            logging.info("Recording started successfully")
            if self.auto_detect:
                logging.info("设备轮询已暂停，录像进行中...")
        else:
            logging.error("Failed to start recording")
            self.is_recording = False

    def stop_recording(self):
        """停止录制"""
        logging.info("Stopping recording...")
        self.is_recording = False
        
        # 停止 GStreamer 进程
        if self.ffmpeg_process:
            try:
                self.ffmpeg_process.terminate()
                self.ffmpeg_process.wait(timeout=5)
                logging.info("GStreamer process terminated successfully")
            except subprocess.TimeoutExpired:
                logging.warning("GStreamer process did not terminate gracefully, killing it")
                self.ffmpeg_process.kill()
                self.ffmpeg_process.wait()
            except Exception as e:
                logging.error(f"Error terminating GStreamer process: {e}")
            finally:
                self.ffmpeg_process = None
        
        # 停止错误监控线程
        if self.error_monitor_thread and self.error_monitor_thread.is_alive():
            self.error_monitor_thread.join(timeout=2.0)
            logging.info("GStreamer error monitor thread stopped")
        
        # 停止RTSP推流进程
        if self.rtsp_process:
            try:
                self.rtsp_process.terminate()
                self.rtsp_process.wait(timeout=5)
                logging.info("RTSP process terminated successfully")
            except subprocess.TimeoutExpired:
                logging.warning("RTSP process did not terminate gracefully, killing it")
                self.rtsp_process.kill()
                self.rtsp_process.wait()
            except Exception as e:
                logging.error(f"Error terminating RTSP process: {e}")
            finally:
                self.rtsp_process = None
        
        # 如果启用了HDMI显示，重新启动lightdm服务
        if self.enable_hdmi_display:
            self._manage_lightdm_service('start')
        
        logging.info("Recording stopped successfully")
        if self.auto_detect:
            logging.info("设备轮询已恢复，继续监控设备状态...")

    def start_http_server(self):
        """启动 HTTP 服务器"""
        try:
            self.http_server_thread = threading.Thread(target=self.server.run, daemon=True)
            self.http_server_thread.start()
            logging.info("HTTP server started")
        except Exception as e:
            logging.error(f"Error starting HTTP server: {e}")

    def start(self):
        """启动录制和推流"""
        # 根据enable_gpio状态决定是否自动开始录像
        if self.enable_gpio:
            # GPIO启用时，默认不开启录像，等待按键操作
            self.is_recording = False
            logging.info("GPIO已启用，等待按键操作开始录像")
        else:
            # GPIO禁用时，默认开启录像
            self.is_recording = True
            logging.info("GPIO已禁用，自动开始录像")
        
        # 启动GPIO监控
        self.start_gpio_monitoring()
        
        # 启动SD卡监控
        self.start_sd_monitoring()
        
        # 启动设备轮询（如果启用自动检测）
        self.start_device_polling()
        
        # 清理旧文件
        self.cleanup_old_files()
        
        # 启动设备监控
        self.start_device_monitor()
        
        # 启动 HTTP 服务器
        self.start_http_server()
        
        # 如果设备已经存在且需要开始录像，则开始录制
        if os.path.exists(self.usb_device):
            if self.is_recording:
                logging.info(f"Camera device {self.usb_device} already exists, starting recording")
                self.start_recording()
            else:
                logging.info(f"Camera device {self.usb_device} ready, waiting for button press")
        else:
            if self.is_recording:
                logging.info(f"Waiting for camera device {self.usb_device} to be connected...")
            else:
                logging.info(f"Waiting for camera device {self.usb_device} and button press...")
        
        # 保持程序运行
        disk_check_counter = 0  # 磁盘检查计数器
        last_file_size = 0  # 记录上次文件大小
        last_check_time = time.time()  # 记录上次检查时间
        
        while True:
            time.sleep(10)
            disk_check_counter += 1
            
            # 每30秒检查一次磁盘空间
            if disk_check_counter >= 3:
                disk_check_counter = 0
                storage_info = self.get_storage_info()
                if storage_info and storage_info['percent'] > 80:
                    logging.warning(f"磁盘使用率过高: {storage_info['percent']:.1f}%，开始清理...")
                    self.cleanup_old_files()
            
            # 只在录制时才检查GStreamer健康状态
            if self.is_recording:
                if not self._check_ffmpeg_health():
                    logging.warning("GStreamer进程异常，尝试自动重启...")
                    if os.path.exists(self.usb_device):
                        # 如果设备存在，尝试重启
                        threading.Thread(target=self._restart_ffmpeg_process, daemon=True).start()
                    else:
                        # 如果设备不存在，启用设备发现轮询
                        logging.warning("USB设备不存在，启用设备发现轮询...")
                        if self.auto_detect:
                            # 确保设备轮询正在运行
                            if not self.device_polling_active:
                                self.start_device_polling()
                            logging.info("设备轮询已启动，将自动寻找可用设备")
                        else:
                            logging.info("自动检测已禁用，等待手动设备连接...")

    def stop(self):
        """停止所有服务"""
        logging.info("Stopping all services...")
        self.is_recording = False
        
        # 停止设备轮询
        self.stop_device_polling()
        
        # 停止设备监控
        self.stop_device_monitor()
        
        # 停止GPIO监控
        self.stop_gpio_monitoring()
        
        # 停止 SD 卡监控
        self.stop_sd_monitoring()
        
        # 停止 HTTP 服务器
        if self.http_server_thread and self.http_server_thread.is_alive():
            self.http_server_thread.join(timeout=2.0)
            logging.info("HTTP server stopped")
        
        # 停止录制
        self.stop_recording()
        
        logging.info("All services stopped")

    def signal_handler(self, signum, frame):
        """信号处理函数"""
        logging.info(f"Received signal {signum}, shutting down...")
        self.stop()
        sys.exit(0)

    def stop_streaming(self):
        """停止推流"""
        try:
            if hasattr(self, 'push_process') and self.push_process:
                logging.info(f"停止推流进程 PID: {self.push_process.pid}")
                self.push_process.terminate()
                self.push_process.wait(timeout=5)
                self.push_process = None
                logging.info("推流已停止")
        except Exception as e:
            logging.error(f"停止推流失败: {e}")
            # 强制结束进程
            if self.push_process:
                self.push_process.kill()
                self.push_process = None

    def handle_push_request(self, file_path):
        """处理推流请求"""
        try:
            # 停止现有的推流
            self.stop_streaming()
            
            # 构建ffmpeg命令
            cmd = [
                'ffmpeg',
                '-re',  # 以实时速率读取输入
                '-i', file_path,  # 输入文件
                '-c', 'copy',  # 直接复制流，不重新编码
                '-f', 'rtsp',  # 输出格式为RTSP
                f'rtsp://localhost:8554/stream{file_path}'  # RTSP URL
            ]
            
            # 启动推流进程
            self.push_process = subprocess.Popen(
                cmd,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE
            )
            
            # 保存文件路径信息
            self.push_process.file_path = file_path
            
            logging.info(f"开始推流: {' '.join(cmd)}")
            logging.info(f"推流进程已启动，PID: {self.push_process.pid}")
            
            return True
        except Exception as e:
            logging.error(f"启动推流失败: {e}")
            return False

    def handle_stop_request(self, file_path):
        """处理停止推流请求"""
        try:
            if self.current_stream:
                # 检查当前推流的文件路径是否匹配
                if hasattr(self.current_stream, 'file_path') and self.current_stream.file_path == file_path:
                    logging.info(f"停止推流进程 PID: {self.current_stream.pid}")
                    
                    # 获取进程组ID
                    pgid = os.getpgid(self.current_stream.pid)
                    
                    # 终止整个进程组
                    os.killpg(pgid, signal.SIGTERM)
                    
                    # 等待进程结束
                    try:
                        self.current_stream.wait(timeout=5)
                    except subprocess.TimeoutExpired:
                        # 如果进程没有及时结束，强制终止
                        os.killpg(pgid, signal.SIGKILL)
                        self.current_stream.wait()
                    
                    self.current_stream = None
                    logging.info(f"推流已停止: {file_path}")
                else:
                    logging.warning(f"当前没有匹配的推流进程: {file_path}")
                
        except Exception as e:
            logging.error(f"停止推流失败: {e}")
            # 确保进程被终止
            if self.current_stream:
                try:
                    os.killpg(os.getpgid(self.current_stream.pid), signal.SIGKILL)
                except:
                    pass
            self.current_stream = None
            raise

    def run(self):
        """运行服务器"""
        try:
            self.server.run()
        except KeyboardInterrupt:
            logging.info("服务器正在关闭...")
            if self.current_stream:
                self.handle_stop_request()
        except Exception as e:
            logging.error(f"服务器运行错误: {e}")
            if self.current_stream:
                self.handle_stop_request()
        finally:
            logging.info("服务器已关闭")

    def _manage_lightdm_service(self, action):
        """
        管理lightdm服务
        
        Args:
            action: 'stop' 或 'start'
        """
        try:
            if action == 'stop':
                logging.info("停止lightdm服务...")
                result = subprocess.run(['systemctl', 'stop', 'lightdm'], 
                                      capture_output=True, text=True, timeout=10)
                if result.returncode == 0:
                    logging.info("lightdm服务已停止")
                else:
                    logging.warning(f"停止lightdm服务失败: {result.stderr}")
                    
            elif action == 'start':
                logging.info("启动lightdm服务...")
                result = subprocess.run(['systemctl', 'start', 'lightdm'], 
                                      capture_output=True, text=True, timeout=10)
                if result.returncode == 0:
                    logging.info("lightdm服务已启动")
                else:
                    logging.warning(f"启动lightdm服务失败: {result.stderr}")
                    
        except Exception as e:
            logging.error(f"管理lightdm服务失败: {e}")

    def _check_ffmpeg_health(self):
        """检查GStreamer进程的健康状况"""
        try:
            if not self.ffmpeg_process:
                logging.error("GStreamer is none")
                self.is_recording = False
                return False
            
            if self.ffmpeg_process.poll() is not None:
                logging.error("GStreamer process exited unexpectedly")
                self.is_recording = False
                self.ffmpeg_process = None  # 清理进程引用
                return False
            
            # 检查进程是否还在运行
            if not self._is_process_alive(self.ffmpeg_process.pid):
                logging.error("GStreamer process is not alive")
                self.is_recording = False
                self.ffmpeg_process = None  # 清理进程引用
                return False
            
            # 检查是否有文件在增长（如果正在录制）
            if self.is_recording:
                if not self._check_file_growth():
                    logging.warning("GStreamer process is running but files are not growing")
                    return False
            
            return True
            
        except Exception as e:
            logging.error(f"检查GStreamer进程健康状况失败: {e}")
            return False

    def _is_process_alive(self, pid):
        """检查进程是否还活着"""
        try:
            os.kill(pid, 0)  # 发送信号0，不实际发送信号，只检查进程是否存在
            return True
        except OSError:
            return False

    def _check_file_growth(self):
        """检查录制文件是否在增长"""
        try:
            # 获取当前日期目录
            current_date_dir = self.get_current_date_dir()
            if not os.path.exists(current_date_dir):
                return False
            
            # 查找最新的MP4文件
            mp4_files = [f for f in os.listdir(current_date_dir) if f.endswith('.mp4')]
            if not mp4_files:
                return False
            
            # 按修改时间排序，获取最新的文件
            latest_file = max(mp4_files, key=lambda f: os.path.getmtime(os.path.join(current_date_dir, f)))
            latest_file_path = os.path.join(current_date_dir, latest_file)
            
            # 检查文件修改时间是否在最近30秒内
            file_mtime = os.path.getmtime(latest_file_path)
            if time.time() - file_mtime < 30:
                # 如果文件存在且最近有修改，就认为文件在增长
                # 不再要求文件大小超过1MB
                return True
            
            return False
            
        except Exception as e:
            logging.error(f"检查文件增长失败: {e}")
            return False

    def _restart_ffmpeg_process(self):
        """重启GStreamer进程"""
        try:
            logging.info("尝试重启GStreamer进程...")
            
            # 停止当前进程
            if self.ffmpeg_process:
                try:
                    self.ffmpeg_process.terminate()
                    self.ffmpeg_process.wait(timeout=5)
                except subprocess.TimeoutExpired:
                    self.ffmpeg_process.kill()
                    self.ffmpeg_process.wait()
                except Exception as e:
                    logging.error(f"停止GStreamer进程失败: {e}")
                finally:
                    self.ffmpeg_process = None
            
            # 等待一段时间
            time.sleep(2)
            
            # 检查设备是否可用
            if not os.path.exists(self.usb_device):
                logging.error("设备不可用，无法重启GStreamer")
                # 如果设备不存在且启用自动检测，确保设备轮询正在运行
                if self.auto_detect and not self.device_polling_active:
                    logging.info("启动设备轮询以寻找可用设备...")
                    self.start_device_polling()
                return False
            
            # 重新启动录制
            current_date_dir = self.get_current_date_dir()
            if self.start_ffmpeg_recording(current_date_dir):
                logging.info("GStreamer进程重启成功")
                # 重启成功后恢复录制状态
                self.is_recording = True
                return True
            else:
                logging.error("GStreamer进程重启失败")
                return False
                
        except Exception as e:
            logging.error(f"重启GStreamer进程失败: {e}")
            return False

    def _start_ffmpeg_error_monitor(self):
        """启动GStreamer错误监控线程"""
        try:
            def ffmpeg_error_monitor():
                while self.ffmpeg_process and self.ffmpeg_process.poll() is None:
                    try:
                        if self.ffmpeg_process.stderr:
                            error_line = self.ffmpeg_process.stderr.readline().decode().strip()
                            if error_line:
                                # 检查是否是严重错误
                                if any(keyword in error_line.lower() for keyword in 
                                       ['error', 'failed', 'invalid', 'cannot', 'unable']):
                                    logging.error(f"GStreamer严重错误: {error_line}")
                                    # 如果是严重错误，可以考虑重启
                                    if 'device busy' in error_line.lower() or 'no such device' in error_line.lower():
                                        logging.error("检测到设备错误，准备重启GStreamer")
                                        threading.Thread(target=self._restart_ffmpeg_process, daemon=True).start()
                                else:
                                    logging.debug(f"GStreamer信息: {error_line}")
                    except Exception as e:
                        logging.error(f"GStreamer错误监控异常: {e}")
                        break
                    time.sleep(0.1)
            
            self.error_monitor_thread = threading.Thread(target=ffmpeg_error_monitor, daemon=True)
            self.error_monitor_thread.start()
            logging.info("GStreamer错误监控线程已启动")
        except Exception as e:
            logging.error(f"启动GStreamer错误监控线程失败: {e}")

if __name__ == "__main__":
    # 使用自动检测功能创建VideoRecorder实例
    recorder = VideoRecorder(
        auto_detect=True,  # 启用自动检测
        enable_gpio=True,  # 启用GPIO控制
        enable_hdmi_display=False  # 启用HDMI显示
    )
    
    try:
        # 显示检测到的设备信息
        available_devices = recorder.get_available_devices()
        logging.info(f"检测到的可用设备: {available_devices}")
        logging.info(f"当前使用的设备: {recorder.usb_device}")
        
        # 启动录制器
        recorder.start()
        
        # 主循环
        while True:
            time.sleep(1)
            
    except KeyboardInterrupt:
        logging.info("收到中断信号，正在关闭...")
        recorder.stop()
        logging.info("程序已退出")
    except Exception as e:
        logging.error(f"程序运行错误: {e}")
        recorder.stop()
        sys.exit(1) 